package com.dycong.common.reflect.Reflect;


import com.dycong.common.reflect.Reflect.fruits.Apple;
import com.dycong.common.reflect.Reflect.fruits.Orange;
import com.dycong.common.reflect.Reflect.fruits.fruit;

import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Created by ${dycong} on 2016/12/9.
 */
public class FruitFactory {

    /*利用反射机制的工厂类*/
    public static fruit getInstance(String ClassName) {
        fruit f = null;
        try {
            f = (fruit) Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }


    public void test() {
        fruit f = FruitFactory.getInstance("Reflect.fruits.Apple");
        if (f != null) {
            f.eat();
        }
    }


    public static String init(String ClassName) {
        Properties prop = new Properties();
        File f = new File("fruit.properties");
        try {
            if (f.exists()) {
                prop.load(new FileInputStream(f));
            } else {
                prop.setProperty("apple", "Reflect.fruits.Apple");
                prop.setProperty("orange", "Reflect.fruits.Orange");
                prop.store(new FileOutputStream(f), "FRUIT CLASS");
            }
        } catch (FileNotFoundException ex) {
            System.out.println(ex);
        } catch (IOException e) {
            System.out.println(e);
        }
        return prop.getProperty(ClassName);
    }


    /*利用反射机制的工厂类*/
    public static fruit getInstanceByProperty(String ClassName) {
        String className = init(ClassName);
        fruit f = null;
        try {
            f = (fruit) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }

    public void test1() {
        Apple f = (Apple) FruitFactory.getInstanceByProperty("apple");
        if (f != null) {
            f.setColor("black");
            f.setName("appal");
            f.eat();
        }

        Orange o = (Orange) FruitFactory.getInstanceByProperty("orange");
        if (o != null) {
            o.setColor("black");
            o.setName("orange");
            o.eat();
        }
    }

    public void test2() throws ClassNotFoundException {

       /* 而另一個版本可以讓您指定類別名稱、載入類別時是否執行靜態區塊、指定類別載入器（Class loader）：
       Class.forName(String name, boolean initialize, ClassLoader loader)*/

        Class<?> clazz = Class.forName("Reflect.fruits.Apple");
        Map<String, String> map = new HashMap<>();


        /*字段*/
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            map.put(field.getName(), field.getType().getSimpleName());
        }
        map.put("------", "------");

        /*方法*/
        Method[] methods = clazz.getMethods();
        for (Method method : methods)
            map.put(method.getName(), method.getGenericParameterTypes().toString());

        try {
            Method method = clazz.getMethod("eat");
            method.invoke(clazz.getConstructors()[1].newInstance("black", "apple"));
            method.invoke(clazz.newInstance());
        } catch (Exception e) {
            System.out.println(e);
        }


        for (Map.Entry entry : map.entrySet())
            System.out.println(entry.getKey() + "=" + entry.getValue());

        /*构造方法*/
        Constructor<?>[] cons = clazz.getConstructors();
        try {
            fruit fr = (fruit) cons[1].newInstance("black", "apple");
            fruit f = (fruit) cons[1].newInstance("black", "apple");
            f.eat();
        } catch (Exception e) {
            System.out.println(e);
        }

        /*获得指定构造方法(指定构造参数)*/
        try {
            Class[] params = new Class[2];
            params[0] = String.class;
            params[1] = String.class;
            Constructor constructor = clazz.getConstructor(params);
            Object[] obj = new Object[2];
            obj[0] = "black";
            obj[1] = "apple";
            /*传入构造方法参数.class类型数组obj*/
            fruit frt = (fruit) constructor.newInstance(obj);
            frt.eat();

            Class[] par = new Class[0];
            /*获得指定方法名以及指定参数类型的.class类型数组par的方法*/
            Method method = clazz.getMethod("eat", par);
            /*通过calss实例，以及参数列表执行方法，此处eat()方法无参，不可以传入参数*/
            method.invoke(clazz.newInstance());
//            method.invoke(clazz.newInstance(),obj);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /*儘管直接存取類別的資料成員（Field）是不被鼓勵的，但您仍是可以直接存取公開的（public）資料成員，而您甚至也可以透過反射機制來存取私用資料成員，
    * 应该通过Method.invoke()方法调用set()*/
    public void test3() throws Exception {
        Class<?> clazz = Class.forName("Reflect.fruits.Apple");
        Object target = clazz.newInstance();
        Field name = clazz.getDeclaredField("name");
        Field color = clazz.getDeclaredField("color");
        name.setAccessible(true);
        name.set(target, "apple");
        color.setAccessible(true);
        color.set(target, "black");
        System.out.println(target);
    }



    public void test4() {
        Class c = String.class;
        Object objArr = Array.newInstance(c, 5);

        for (int i = 0; i < 5; i++) {
            Array.set(objArr, i, i + "");
        }

        for (int i = 0; i < 5; i++) {
            System.out.print(Array.get(objArr, i) + " ");
        }
        System.out.println();

        String[] strs = (String[]) objArr;
        for (String s : strs) {
            System.out.print(s + " ");
        }
    }


    public void test5() {
        Class c = String.class;

        // 打算建立一個3*4陣列
        int[] dim = new int[]{3, 4};
        Object objArr = Array.newInstance(c, dim);

        for (int i = 0; i < 3; i++) {
            /*先获得行*/
            Object row = Array.get(objArr, i);
            for (int j = 0; j < 4; j++) {
                Array.set(row, j, "" + (i + 1) * (j + 1));
            }
        }

        for (int i = 0; i < 3; i++) {
            Object row = Array.get(objArr, i);
            for (int j = 0; j < 4; j++) {
                System.out.print(Array.get(row, j) + " ");
            }
            System.out.println();
        }
    }

}

